﻿<?php


/* 
CSS Star Rating Snippet for MODx Content Management Framework (http://modxcms.com)
Copyright (C) 2007 Garry Nutting
*/

/*
 * Generates and handles the processing for a star rating based on the given properties
 */
class rating {

	var $templateVar;
	var $useCookie; //was $onevote
	var $useSession;
	var $viewOnly;
	var $maxStars = 5;
	var $imgWidth = 25;
	var $cookieExpiry = 604800; //was $ovtime
	var $snippetPath;
	var $starTpl = '[+starRating+]<span class="totalvotes">Votes: [+totalVotes+]</span>';
	var $debug = false;
	var $webGroups = false;
	var $redirect;
	var $lang = 'english';
	var $sessionName = 'starRating';
	var $cookieName = 'starRating';
	var $theme = 'default';
	var $cssFile = 'star_rating';

	var $_passedId;
	var $_templateVarMeta = array ();
	var $_placeholderArray = array ();
	var $_lang = array ();
	var $_debug = '';
	var $_tvId;
	var $_cookieKey;
	var $_sessionKey;
	var $_keysObtained = false;

	function rating($docId) {
		$this->__construct($docId);
	}

	function __construct($docId) {
		session_start();
		$this->_passedId = $docId;
		if (!$this->_keysObtained) {
			$this->__getKeys();
		}
	}

	/*
	 * Parses the stored TV value into separated vote statistics
	 */
	function getVote() {
		global $modx;

		$splitVals = array ();
		$this->_templateVarMeta = count($this->_templateVarMeta) == 0 ? $modx->getTemplateVar($this->templateVar, '*', $this->_passedId) : $this->_templateVarMeta;
		if (is_array($this->_templateVarMeta) && array_key_exists('value', $this->_templateVarMeta) && preg_match('/^[\d]+:[\d]+$/', $this->_templateVarMeta['value'])) {
			$splitVals = explode(':', $this->_templateVarMeta['value']);
			$this->_templateVarMeta['average'] = $splitVals[0] / $splitVals[1];
			$this->_templateVarMeta['total'] = $splitVals[1];
		} else {
			$this->_templateVarMeta['average'] = 0;
			$this->_templateVarMeta['total'] = 0;
		}
	}

	/*
	 * Checks if a vote has been made and if the vote is valid, stores the vote to the TV
	 */
	function setVote() {
		global $modx;
		if (!$this->__disallowVoting()) {
			if ($this->_passedId <> '' && isset ($_GET['starvote']) && is_numeric($_GET['starvote']) && $_GET['starvote'] >= 0 && $_GET['starvote'] <= $this->maxStars) {
				// get TV value
				$tvValue = $modx->getTemplateVar($this->templateVar, '*', $this->_passedId);
	
				// split out TV values and calculate current Rating
				$splitVals = explode(':', $tvValue['value']);
	
				$newCount = $splitVals[0] + $_GET['starvote'];
				$newVoteNumber = $splitVals[1] + 1;
	
				if (!$this->__setTemplateVar("$newCount:$newVoteNumber", $this->_passedId, $this->templateVar) && $this->debug) {
					$this->__debug('Unable to save TV Value');
					return false;
				}
				if ($this->useCookie == true) {
					$this->__setKey('cookie');
				}
				if ($this->useSession == true) {
					$this->__setKey('session');
				}
				unset ($_GET);
	
				// refresh page to show correct ratings
				$curURL = $modx->makeUrl($this->redirect);
				$modx->sendRedirect($curURL);
			}
		}
	}

	/*
	 * Renders the vote for screen output
	 */
	function renderVote() {
		global $modx;

		if ($this->_passedId) {
			$this->__getLang();
			$this->getVote();
			$currentPercentage = floor(($this->_templateVarMeta['average']/$this->maxStars)*100);
			$currentText = $this->_lang['current']. $this->_templateVarMeta['average'].'/'.$this->maxStars;
			$listItems = '';

			for($i = 0; $i <= $this->maxStars ; $i++) {
				if ($i == 0) {
					$listItems .= '<li class="current-rating" style="width:'. $currentPercentage. '%;">'.$currentText.'</li>';
				} else {
					$starWidth = floor(100 / $this->maxStars * $i);
					$starIndex = ($this->maxStars - $i) + 2;
					if (!$this->__disallowVoting()) {
						$listItems .= '<li class="star"><a href="'. $modx->makeUrl($modx->documentObject['id'], '', 'starvote='.$i.'&amp;pid=' . $this->_passedId) . '" title="' . $i . '/' . $this->maxStars . '" style="width:'.$starWidth .'%;z-index:'.$starIndex . '">'. $i . '</a></li>';
					} else {
						$listItems .= '<li class="star"><span>'. $i .'</span></li>';
					}
				}
				$this->_placeholderArray['starRating'] = '<ul class="star-rating-'.$this->theme.'" style="width:'.$this->maxStars * $this->imgWidth.'px;" >' . $listItems . '</ul>';
			}

			$this->_placeholderArray['totalVotes'] = $this->_templateVarMeta['total'];

			foreach ($this->_placeholderArray as $n => $v) {
				$this->starTpl = str_replace('[+' . $n . '+]', $v, $this->starTpl);
			}
			$output = '';
			$output .= $this->starTpl;
			return $output;
		} else {
			$this->__debug('Unable to render star rating, passedId is not set');
			return false;
		}
	}

	/*
	 * Outputs the CSS using the $modx->regClientCSS() method
	 */
	function loadTheme() {
		global $modx;
		if (file_exists(MODX_BASE_PATH.'assets/snippets/star_rating/themes/'.$this->theme.'/'.$this->cssFile.'.css')) {
			$modx->regClientCSS(MODX_BASE_URL.'assets/snippets/star_rating/themes/'.$this->theme.'/'.$this->cssFile.'.css');
		} else {
			$this->__debug('Unable to output the CSS');
			return false;
		}
	}

	/*
	 * Loads the language file for use in the class
	 */
	function __getLang() {
		global $modx;
		$_lang = array ();
		include $modx->config['base_path'] . 'assets/snippets/star_rating/lang/english.inc.php';
		if ($this->lang && file_exists($modx->config['base_path'] . 'assets/snippets/star_rating/lang/' . $this->lang . '.inc.php')) {
			include $modx->config['base_path'] . 'assets/snippets/star_rating/lang/' . $this->lang . '.inc.php';
		}
		$this->_lang = $_lang;
	}

	/*
	 * Sets the template variable based on the values passed into the method
	 */
	function __setTemplateVar($value, $docID, $tplVarName) {
		global $modx;

		// get tmplvar id
		$tplName = $modx->getFullTableName('site_tmplvars');
		$tplRS = $modx->db->select('id', $tplName, 'name="' . $tplVarName . '"');
		$tplRow = $modx->db->getRow($tplRS);

		$tblName = $modx->getFullTableName('site_tmplvar_contentvalues');

		$selectQuery = $modx->db->select('*', $tblName, 'contentid=' . $docID . ' AND tmplvarid=' . $tplRow['id']);

		$updFields = array (
			'value' => $value
		);
		$insFields = array (
			'tmplvarid' => $tplRow['id'],
			'contentid' => $docID,
			'value' => $value
		);

		// check if record needs to be inserted or updated
		if ($modx->db->getRecordCount($selectQuery) < 1) {
			$modx->db->insert($insFields, $tblName);
		} else {
			$modx->db->update($updFields, $tblName, 'contentid=' . $docID . ' AND tmplvarid=' . $tplRow['id']);
		}
	}

	/*
	 * Checks permissions and properties to see if voting is disallowed
	 */
	function __disallowVoting() {
		if ($this->webGroups !== false && $this->__checkMembership() == false) {
			return true;
		}

		if ($this->useCookie == true && in_array($this->_passedId, $this->_cookieKey) === true) {
			$this->viewOnly = true;
			return true;
		}
		elseif ($this->useSession == true && in_array($this->_passedId, $this->_sessionKey) === true) {
			$this->viewOnly = true;
			return true;
		} else {
			$this->viewOnly = $this->viewOnly ? $this->viewOnly : false;
			return false;
		}
	}

	/*
	 * Check if the user is allowed to vote based on web group membership (only if webGroups property has been set)
	 */
	function __checkMembership() {
		global $modx;
		$permGranted = false;

		if ($this->webGroups !== false && isset ($_SESSION['webInternalKey'])) {
			$groupArray = explode(',', $this->webGroups);
			if (count($groupArray) > 0) {
				foreach ($groupArray as $k => $v) {
					$groupArray[$k] = trim($v);
				}
				$tbl = $modx->getFullTableName('webgroup_names');
				$tbl2 = $modx->getFullTableName('web_groups');
				$sql = "SELECT wgn.name FROM $tbl wgn INNER JOIN $tbl2 wg ON wg.webgroup=wgn.id AND wg.webuser='" . $_SESSION['webInternalKey'] . "'";
				$rs = $modx->db->query($sql);
				if ($modx->db->getRecordCount($rs) > 0) {
					while ($row = $modx->db->getRow($rs)) {
						if (in_array($row['name'], $groupArray)) {
							$permGranted = true;
						}
					}
				}
			}
		} else {
			$permGranted = true;
		}
		return $permGranted;
	}

	/*
	 * Get the session and cookie keys
	 */
	function __getKeys() {
		global $modx;

		if (array_key_exists($this->sessionName,$_SESSION)) {
			$this->_sessionKey = $_SESSION[$this->sessionName];
		} else {
			$this->_sessionKey = array ();
		}

		if (array_key_exists($this->cookieName, $_COOKIE)) {
			$cArray = explode(',',$_COOKIE[$this->cookieName]);
			if (!is_array($cArray)) $cArray = array();
			$this->_cookieKey = $cArray;
		} else {
			$this->_cookieKey = array ();
		}
		
		$this->_keysObtained = true;
	}

	/*
	 * Set the cookie or session values to their required values
	 */
	function __setKey($type) {
		switch ($type) {
			case 'session' :
				if(!array_key_exists($this->sessionName, $_SESSION)) $_SESSION[$this->sessionName] = array();
				if (!in_array($this->_passedId,$_SESSION[$this->sessionName])) {
					array_push($_SESSION[$this->sessionName], $this->_passedId);
				}
				session_write_close();
				return true;
			case 'cookie' :
				$cArray = explode(',',$_COOKIE[$this->cookieName]);
				if (!is_array($cArray)) $cArray = array();
				if(!in_array($this->_passedId,$cArray)) {
					array_push($cArray, $this->_passedId);
					setcookie($this->cookieName, implode(',',$cArray), time() + $this->cookieExpiry);
				}
				return true;
		}
	}

	/*
	 * Simple debug output method
	 */
	function __debug($message) {
		$this->_debug .= '<p>' . $message . '</p>';
	}
}
?>